package cn.labbook.bluetooth.util.file;

import cn.labbook.bluetooth.pojo.dto.UploadDTO;
import cn.labbook.bluetooth.util.ImageUtils;
import cn.labbook.bluetooth.util.StringUtils;
import cn.labbook.bluetooth.util.TimeUtils;
import org.apache.commons.io.IOUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Calendar;
import java.util.Date;
import java.util.UUID;

/**
 * 文件Utils
 * @author chenjunhui 
 */
@Component
public class FileUtils {

	private final static Logger logger = LoggerFactory.getLogger(FileUtils.class);

	public static final String FILE_SEPARATOR = "/";

	public static final double compress_image_rate = 1.50;//图片压缩比。建议1.5倍长宽压缩
	public static final int compress_image_size = 1048576;//图片压缩线。单位byte。当前是1MB

	@Value("${imgRoot}")
	private String imgRoot;
	@Value("${file-upload-path}")
	private String fileUploadPath;


	/**
	 * 上传单个文件
	 *
	 * @param file		文件
	 * @return			文件地址
	 */
	public UploadDTO uploadSingle(MultipartFile file) {
		if (file == null || file.isEmpty()) {
			return new UploadDTO();
		}

		//保存上传文件
		String oldName = file.getOriginalFilename();
		String filePath;
		try {
			filePath = FileUtils.saveFile(file.getInputStream(),
					fileUploadPath,
					oldName, file.getContentType());
			//压缩图片
			filePath = compressImage(file, filePath);
		} catch (IOException e) {
			throw new RuntimeException(e);
		}
		return new UploadDTO(imgRoot + filePath);
	}

	/**
	 * 压缩图片。
	 *
	 * @param file。文件
	 * @param oldImageHalfPath 。已经保存的旧文件半链接地址
	 * @return
	 * @throws FileNotFoundException
	 * @throws IOException
	 */
	public String compressImage(MultipartFile file, String oldImageHalfPath) throws FileNotFoundException, IOException {
		System.out.println("----------图片压缩准备。原始大小：" + file.getSize() + "kb--------------------");
		//如果上传文件是图片，且大小超过1m，就开始压缩
		//文件后缀名
		String oldFileSuffix = oldImageHalfPath.substring(oldImageHalfPath.indexOf(".") + 1, oldImageHalfPath.length());
		System.out.println("----------图片压缩准备。旧路径，后缀名称：" + oldFileSuffix + "--------------------");
		//没有后缀名的文件名
		String oldFileNameNoSuffix = oldImageHalfPath.substring(0, oldImageHalfPath.indexOf("."));
		System.out.println("---------图片压缩准备。旧路径，无后缀名称：" + oldFileNameNoSuffix + "--------------------");
		if (file == null ||
				StringUtils.isEmpty(file.getContentType()) ||
				(!oldFileSuffix.equalsIgnoreCase("jpg") &&
						!oldFileSuffix.equalsIgnoreCase("png")
				) ||
				file.getSize() < compress_image_size) {
			return oldImageHalfPath;

		}
		System.out.println("----------图片压缩开始。原始大小：" + file.getSize() + "kb--------------------");

		Image srcImg = ImageIO.read(new FileInputStream(fileUploadPath + oldImageHalfPath));//取源图

		String widthStr = String.valueOf(Double.valueOf(srcImg.getWidth(null)) / compress_image_rate);
		widthStr = widthStr.substring(0, widthStr.indexOf("."));
		String heightStr = String.valueOf(Double.valueOf(srcImg.getHeight(null)) / compress_image_rate);
		heightStr = heightStr.substring(0, heightStr.indexOf("."));

		//缩减压缩图片的长和宽
		int width = Integer.valueOf(widthStr);
		int height = Integer.valueOf(heightStr);

		Image smallImg = srcImg.getScaledInstance(width, height, Image.SCALE_SMOOTH);//
		BufferedImage bi = new BufferedImage(width, height, BufferedImage.TYPE_3BYTE_BGR);

		//再创建一个Graphics变量，用来画出来要保持的图片，及上面传递过来的Image变量
		Graphics g = bi.getGraphics();
		// try {
		g.drawImage(smallImg, 0, 0, null);


		//将BufferedImage变量写入文件中。
		String newFileHalfPath = oldFileNameNoSuffix + "-1." + oldFileSuffix;

		//新的文件-
		File newFile = new File(fileUploadPath + newFileHalfPath);
		ImageIO.write(bi, oldFileSuffix, newFile);

		System.out.println("----------图片压缩结束.-------------------");
		return newFileHalfPath;
	}

	/**
	 * 请fileDirs不要为空
	 * 
	 * @param fileDirs
	 * @return
	 */
	public static String getFileDir(final String imageDir,String... fileDirs) {
		String dir = imageDir;
		for (String fileDir : fileDirs) {
			dir = dir + FILE_SEPARATOR + fileDir;
		}
		dir += FILE_SEPARATOR;
		File file = new File(dir);
		if (!file.exists()) {
			file.mkdirs();
		}
		return dir;
	}

	public static String getFileName(String savedFilePath,String proFileName, String... fileDirs) {
		return getFileDir(savedFilePath,fileDirs) + getRandomFileName(proFileName);
	}

	public static String getDateFileName(String proFileName) {
		Calendar calendar = Calendar.getInstance();
		calendar.setTime(new Date());
		int year = calendar.get(Calendar.YEAR);
		int month = calendar.get(Calendar.MONTH) + 1;
		String fileName = getFileName(proFileName, String.valueOf(year), String
				.valueOf(month));
		File file = new File(fileName);
		if (!file.exists()) {
			try {
				file.createNewFile();
			} catch (IOException e) {
				e.printStackTrace();
				fileName = null;
			}
		}
		return fileName;
	}

	/**
	 * 先调用其他方法包装proFileName不为空且含有"."
	 * 
	 * @param proFileName
	 * @return
	 */
	public static String getRandomFileName(String proFileName) {
		int length = proFileName.lastIndexOf(".");
		if(length==-1){
			return UUID.randomUUID().toString();
		}
		String suffix = proFileName.substring(length);
		return UUID.randomUUID().toString() + suffix;
	}

	/**
	 * 将FTP地址改成web地址
	 * 
	 * @param ftpDir
	 * @param imgRoot
	 * @return
	 */
	public static String changeToWebRoot(String ftpDir, String imgRoot) {
		int index = ftpDir.indexOf(imgRoot) + imgRoot.length();
		return ftpDir.substring(index).replace(
				System.getProperty("file.separator"), "/");
	}

	public static final String IMG_START = "image/";
	
	/**
	 * 保存文件
	 * @param stream
	 * @param fileName
	 * @param fileContentType
	 * @return
	 */
	public static String saveFile(InputStream stream,String saveImageDir,String fileName, String fileContentType){
		try{
			String realPath = FileUtils.getFileName(saveImageDir,fileName, String
					.valueOf(TimeUtils.getCurrentYear()), String
					.valueOf(TimeUtils.getCurrentMonth()));
			IOUtils.copyLarge(stream, new FileOutputStream(realPath));
			return changeToWebRoot(realPath, saveImageDir);	
		}catch (Exception e) {
			throw new RuntimeException(e);
		}finally{
			try {
				stream.close();
			} catch (IOException e) {
				logger.error("close stream fail",e);
			}
		}
	}
	
	public static String saveFile(File file,String fileName,String saveFileDir, String fileContentType){
		try{
			InputStream stream = new FileInputStream(file);
			return FileUtils.saveFile(stream,saveFileDir, fileName, fileContentType);
		}catch(Exception e){
			throw new RuntimeException(e);
		}
	}
	
	/**
	 * 保存图片 并返回物理路径和 相对web路径
	 * @param file
	 * @param fileName
	 * @param fileContentType
	 * @param width
	 * @param height
	 * @return String[] length=2 String[0] = 物理路径 String[1] = 相对web路径 
	 */
	public static String saveImage(File file,String savedDir,String fileName,String fileContentType,int width,int height){
		try{
			InputStream stream = new FileInputStream(file);
			return saveImage(stream,savedDir,fileName, fileContentType, width, height);
		}catch(Exception e){
			throw new RuntimeException(e);
		}
	}
	
	/**
	 * @param stream
	 * @param saveImageDir 需要保存图片到那个目录
	 * @param fileName
	 * @param fileContentType
	 * @param width
	 * @param height
	 * @return
	 */
	public static String saveImage(
			InputStream stream,String saveImageDir,String fileName, String fileContentType,
			int width, int height
	){
		try {
			if (!StringUtils.startsWith(fileContentType, IMG_START)) {
				throw new RuntimeException("the file type is not image");
			}
			String realPath = FileUtils.getFileName(saveImageDir,fileName, String
					.valueOf(TimeUtils.getCurrentYear()), String
					.valueOf(TimeUtils.getCurrentMonth()));
			if (width > 0 || height > 0) { // 传了限制宽高的话 就压缩
				ImageUtils.saveImageAsJpg(stream, realPath, width, height, true);
			} else {// 不压缩的话 直接保存
				IOUtils.copyLarge(stream, new FileOutputStream(realPath));
			}
			return changeToWebRoot(realPath, saveImageDir);
		} catch (Exception e) {
			throw new RuntimeException(e);
		}finally{
			try {
				stream.close();
			} catch (IOException e) {
				logger.error("close stream fail",e);
			}
		}
	}

	/**
	 * 保存图片 并返回物理路径和 相对web路径
	 * @param file
	 * @param fileName
	 * @param fileContentType
	 * @return String[] length=2 String[0] = 物理路径 String[1] = 相对web路径 
	 */
	public static String saveImage(File file,String savedDir,String fileName,String fileContentType){
		return FileUtils.saveImage(file, savedDir,fileName, fileContentType, 0, 0);
	}

	public static String saveImage(InputStream stream,String savedDir,String fileName,String fileContentType){
		return FileUtils.saveImage(stream, savedDir,fileName, fileContentType, 0, 0);
	}

	/**
	 * 删除目录
	 *
	 * @author fengshuonan
	 * @Date 2017/10/30 下午4:15
	 */
	public static boolean deleteDir(File dir) {
		if (dir.isDirectory()) {
			String[] children = dir.list();
			for (int i = 0; i < children.length; i++) {
				boolean success = deleteDir(new File(dir, children[i]));
				if (!success) {
					return false;
				}
			}
		}
		return dir.delete();
	}

	/**
	 * 读取远程文件
	 *
	 * @param remoteUrl		远程文件地址
	 * @param filePath		本地保存地址
	 * @return				文件流
	 */
	public static File readRemoteFile(String remoteUrl, String filePath) throws IOException {
		HttpURLConnection httpUrl = (HttpURLConnection) new URL(remoteUrl).openConnection();
		httpUrl.connect();
		InputStream ins = httpUrl.getInputStream();
		File file = new File(filePath);
		if (file.exists()) {
			file.delete();//如果缓存中存在该文件就删除
		} else {
			file.createNewFile();
		}
		OutputStream os = new FileOutputStream(file);
		int bytesRead;
		int len = 8192;
		byte[] buffer = new byte[len];
		while ((bytesRead = ins.read(buffer, 0, len)) != -1) {
			os.write(buffer, 0, bytesRead);
		}
		os.close();
		ins.close();
		return file;
	}

	/**
	 * 读取图片
	 *
	 * @param imageUrl		图片地址
	 * @param path			保存后的图片路径
	 */
	public static void readImage(String imageUrl, String path) throws IOException {
		BufferedInputStream bis = null;
		OutputStream bos = null;

		try {
			//实例化url
			URL url = new URL(imageUrl);
			//载入图片到输入流
			bis = new BufferedInputStream(url.openStream());
			//实例化存储字节数组
			byte[] bytes = new byte[100];
			//设置写入路径以及图片名称
			bos = new FileOutputStream(new File(path));
			int len;
			while ((len = bis.read(bytes)) > 0) {
				bos.write(bytes, 0, len);
			}

			//关闭输出流
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			if (bis != null) {
				bis.close();
			}
			if (bos != null) {
				bos.flush();
				bos.close();
			}
		}
	}

}
